package advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * Author:shixiaojun@itany.com
 * Date:2022/5/18 15:51
 * Version:1.0-SNAPSHOT
 * Description:
 */
@Component
// @Aspect注解表示当前类是一个切面
@Aspect
public class LogAdvice {

    // @Pointcut标注在方法上,表示当前方法是一个切点表达式方法
    // 作为切点表达式的方法,不需要做任何的实现
    // 该注解存在value属性,其value属性值即为切点表达式内容
    // 在Spring的所有注解中,有一个共同的特征
    // 当某一个注解的属性有且仅有value的时候,可以直接写属性值
    // 方法名(带上方法的括号)即为切点表达式的id属性值
    // 在此处,id即为:pointcutName()
//    @Pointcut(value = "")
    @Pointcut("execution(* service.impl.*.*(..))")
    public void pointcutName(){}

    // 通知的注解即为配置文件的标签名,使用驼峰命名法
    // 每一个注解均包含value属性,该属性表示指定切入点,相当于配置文件中的pointcut-ref属性
//    @Before(value = "pointcutName()")
    @Before("pointcutName()")
    public void before(JoinPoint jp){
        // 获取目标类
//        Object target = jp.getThis();
        Object target = jp.getTarget();
        // 目标方法
        Signature signature = jp.getSignature();
        // 参数列表
        Object[] args = jp.getArgs();
        System.out.println("前置通知:在"+new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+"执行了"+signature.getName()+"方法,方法的参数为:"+ Arrays.toString(args));
    }

    // returning属性:指定用于接收返回值的参数
    @AfterReturning(value = "pointcutName()",returning = "returnValue")
    public void afterReturning(JoinPoint jp, Object returnValue){
        System.out.println("正常返回通知:"+jp.getSignature().getName()+"方法执行成功,方法的返回值为:"+returnValue);
    }

    // throwing属性:指定用于接收异常的参数
    @AfterThrowing(value = "pointcutName()",throwing = "e")
    public void afterThrowing(JoinPoint jp,Exception e){
        System.out.println("异常通知:"+jp.getSignature().getName()+"执行遇到了异常,异常为:"+e);
    }

    @After(value = "pointcutName()")
    public void after(JoinPoint jp){
        System.out.println("后置通知:"+jp.getSignature().getName()+"执行结束");
    }

    @Around(value = "pointcutName()")
    public Object around(ProceedingJoinPoint jp) throws Throwable{
        Object result = null;

        try {
            System.out.println("环绕通知之前置通知");
            result = jp.proceed();
            System.out.println("环绕通知之正常返回通知,返回值为:"+result);
        } catch (Throwable throwable) {
            System.out.println("环绕通知之异常通知,异常为:"+throwable);
            throw throwable;
        }
        System.out.println("环绕通知之后置通知");
        return result;
    }
}
